]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/Mac OS Test Responder.c
mDNSResponder-107.6.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / Mac OS Test Responder.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 Change History (most recent first):
18
19 $Log: Mac\040OS\040Test\040Responder.c,v $
20 Revision 1.25 2006/08/14 23:24:29 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
22
23 Revision 1.24 2004/12/16 20:49:34 cheshire
24 <rdar://problem/3324626> Cache memory management improvements
25
26 Revision 1.23 2004/09/17 01:08:50 cheshire
27 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
28 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
29 declared in that file are ONLY appropriate to single-address-space embedded applications.
30 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
31
32 Revision 1.22 2004/08/13 23:25:01 cheshire
33 Now that we do both uDNS and mDNS, global replace "m->hostname" with
34 "m->MulticastHostname" for clarity
35
36 Revision 1.21 2004/03/12 21:30:25 cheshire
37 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
38 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
39
40 Revision 1.20 2004/02/09 23:23:32 cheshire
41 Advertise "IL 2\4th Floor.apple.com." as another test "browse domain"
42
43 Revision 1.19 2004/01/24 23:55:15 cheshire
44 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
45
46 Revision 1.18 2003/11/14 21:27:08 cheshire
47 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
48 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
49
50 Revision 1.17 2003/08/14 02:19:54 cheshire
51 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
52
53 Revision 1.16 2003/08/12 19:56:24 cheshire
54 Update to APSL 2.0
55
56 */
57
58 #include <stdio.h> // For printf()
59 #include <string.h> // For strlen() etc.
60
61 #include <Events.h> // For WaitNextEvent()
62 #include <SIOUX.h> // For SIOUXHandleOneEvent()
63
64 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
65
66 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
67
68 // These don't have to be globals, but their memory does need to remain valid for as
69 // long as the search is going on. They are declared as globals here for simplicity.
70 static mDNS m;
71 static mDNS_PlatformSupport p;
72 static ServiceRecordSet p1, p2, afp, http, njp;
73 static AuthRecord browsedomain1, browsedomain2;
74
75 // This sample code just calls mDNS_RenameAndReregisterService to automatically pick a new
76 // unique name for the service. For a device such as a printer, this may be appropriate.
77 // For a device with a user interface, and a screen, and a keyboard, the appropriate
78 // response may be to prompt the user and ask them to choose a new name for the service.
79 mDNSlocal void Callback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
80 {
81 switch (result)
82 {
83 case mStatus_NoError: debugf("Callback: %##s Name Registered", sr->RR_SRV.resrec.name->c); break;
84 case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", sr->RR_SRV.resrec.name->c); break;
85 case mStatus_MemFree: debugf("Callback: %##s Memory Free", sr->RR_SRV.resrec.name->c); break;
86 default: debugf("Callback: %##s Unknown Result %d", sr->RR_SRV.resrec.name->c, result); break;
87 }
88
89 if (result == mStatus_NameConflict) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
90 }
91
92 // RegisterService() is a simple wrapper function which takes C string
93 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
94 mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
95 UInt16 PortAsNumber, const char txtinfo[],
96 const domainlabel *const n, const char type[], const char domain[])
97 {
98 domainname t;
99 domainname d;
100 char buffer[MAX_ESCAPED_DOMAIN_NAME];
101 UInt8 txtbuffer[512];
102
103 MakeDomainNameFromDNSNameString(&t, type);
104 MakeDomainNameFromDNSNameString(&d, domain);
105
106 if (txtinfo)
107 {
108 strncpy((char*)txtbuffer+1, txtinfo, sizeof(txtbuffer)-1);
109 txtbuffer[0] = (UInt8)strlen(txtinfo);
110 }
111 else
112 txtbuffer[0] = 0;
113
114 mDNS_RegisterService(m, recordset,
115 n, &t, &d, // Name, type, domain
116 mDNSNULL, mDNSOpaque16fromIntVal(PortAsNumber),
117 txtbuffer, (mDNSu16)(1+txtbuffer[0]), // TXT data, length
118 mDNSNULL, 0, // Subtypes (none)
119 mDNSInterface_Any, // Interface ID
120 Callback, mDNSNULL); // Callback and context
121
122 ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
123 printf("Made Service Records for %s\n", buffer);
124 }
125
126 // RegisterFakeServiceForTesting() simulates the effect of services being registered on
127 // dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
128 mDNSlocal void RegisterFakeServiceForTesting(mDNS *m, ServiceRecordSet *recordset, const char txtinfo[],
129 const char name[], const char type[], const char domain[])
130 {
131 static UInt16 NextPort = 0xF000;
132 domainlabel n;
133 MakeDomainLabelFromLiteralString(&n, name);
134 RegisterService(m, recordset, NextPort++, txtinfo, &n, type, domain);
135 }
136
137 // CreateProxyRegistrationForRealService() checks to see if the given port is currently
138 // in use, and if so, advertises the specified service as present on that port.
139 // This is useful for advertising existing real services (Personal Web Sharing, Personal
140 // File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves.
141 mDNSlocal OSStatus CreateProxyRegistrationForRealService(mDNS *m, UInt16 PortAsNumber, const char txtinfo[],
142 const char *servicetype, ServiceRecordSet *recordset)
143 {
144 InetAddress ia;
145 TBind bindReq;
146 OSStatus err;
147 TEndpointInfo endpointinfo;
148 EndpointRef ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &endpointinfo, &err);
149 if (!ep || err) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err); return(err); }
150
151 ia.fAddressType = AF_INET;
152 ia.fPort = mDNSOpaque16fromIntVal(PortAsNumber).NotAnInteger;
153 ia.fHost = 0;
154 bindReq.addr.maxlen = sizeof(ia);
155 bindReq.addr.len = sizeof(ia);
156 bindReq.addr.buf = (UInt8*)&ia;
157 bindReq.qlen = 0;
158 err = OTBind(ep, &bindReq, NULL);
159
160 if (err == kOTBadAddressErr)
161 RegisterService(m, recordset, PortAsNumber, txtinfo, &m->nicelabel, servicetype, "local.");
162 else if (err)
163 debugf("OTBind failed %d", err);
164
165 OTCloseProvider(ep);
166 return(noErr);
167 }
168
169 // Done once on startup, and then again every time our address changes
170 mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m)
171 {
172 char buffer[MAX_ESCAPED_DOMAIN_NAME];
173 mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4;
174
175 ConvertDomainNameToCString(&m->MulticastHostname, buffer);
176 printf("Name %s\n", buffer);
177 printf("IP %d.%d.%d.%d\n", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
178
179 printf("\n");
180 printf("Registering Service Records\n");
181 // Create example printer discovery records
182 //static ServiceRecordSet p1, p2;
183
184 #define SRSET 0
185 #if SRSET==0
186 RegisterFakeServiceForTesting(m, &p1, "path=/index.html", "Web Server One", "_http._tcp.", "local.");
187 RegisterFakeServiceForTesting(m, &p2, "path=/path.html", "Web Server Two", "_http._tcp.", "local.");
188 #elif SRSET==1
189 RegisterFakeServiceForTesting(m, &p1, "rn=lpq1", "Epson Stylus 900N", "_printer._tcp.", "local.");
190 RegisterFakeServiceForTesting(m, &p2, "rn=lpq2", "HP LaserJet", "_printer._tcp.", "local.");
191 #else
192 RegisterFakeServiceForTesting(m, &p1, "rn=lpq3", "My Printer", "_printer._tcp.", "local.");
193 RegisterFakeServiceForTesting(m, &p2, "lrn=pq4", "My Other Printer", "_printer._tcp.", "local.");
194 #endif
195
196 // If AFP Server is running, register a record for it
197 CreateProxyRegistrationForRealService(m, 548, "", "_afpovertcp._tcp.", &afp);
198
199 // If Web Server is running, register a record for it
200 CreateProxyRegistrationForRealService(m, 80, "", "_http._tcp.", &http);
201
202 // And pretend we always have an NJP server running on port 80 too
203 //RegisterService(m, &njp, 80, "NJP/", &m->nicelabel, "_njp._tcp.", "local.");
204
205 // Advertise that apple.com. is available for browsing
206 mDNS_AdvertiseDomains(m, &browsedomain1, mDNS_DomainTypeBrowse, mDNSInterface_Any, "apple.com.");
207 mDNS_AdvertiseDomains(m, &browsedomain2, mDNS_DomainTypeBrowse, mDNSInterface_Any, "IL 2\\4th Floor.apple.com.");
208
209 return(kOTNoError);
210 }
211
212 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
213 mDNSlocal Boolean YieldSomeTime(UInt32 milliseconds)
214 {
215 extern Boolean SIOUXQuitting;
216 EventRecord e;
217 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
218 SIOUXHandleOneEvent(&e);
219 return(SIOUXQuitting);
220 }
221
222 int main()
223 {
224 mStatus err;
225 Boolean DoneSetup = false;
226
227 SIOUXSettings.asktosaveonclose = false;
228 SIOUXSettings.userwindowtitle = "\pMulticast DNS Responder";
229
230 printf("Multicast DNS Responder\n\n");
231 printf("This software reports errors using MacsBug breaks,\n");
232 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
233 printf("******************************************************************************\n");
234
235 err = InitOpenTransport();
236 if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
237
238 err = mDNS_Init(&m, &p, mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
239 mDNS_Init_AdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
240 if (err) return(err);
241
242 while (!YieldSomeTime(35))
243 {
244 #if MDNS_ONLYSYSTEMTASK
245 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
246 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
247 extern void mDNSPlatformIdle(mDNS *const m);
248 mDNSPlatformIdle(&m); // Only needed for debugging version
249 #endif
250 if (m.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
251 {
252 DoneSetup = true;
253 printf("\nListening for mDNS queries...\n");
254 mDNSResponderTestSetup(&m);
255 }
256 }
257
258 if (p1.RR_SRV.resrec.RecordType ) mDNS_DeregisterService(&m, &p1);
259 if (p2.RR_SRV.resrec.RecordType ) mDNS_DeregisterService(&m, &p2);
260 if (afp.RR_SRV.resrec.RecordType ) mDNS_DeregisterService(&m, &afp);
261 if (http.RR_SRV.resrec.RecordType) mDNS_DeregisterService(&m, &http);
262 if (njp.RR_SRV.resrec.RecordType ) mDNS_DeregisterService(&m, &njp);
263
264 mDNS_Close(&m);
265
266 return(0);
267 }